package cn.lg.soar.system.api.service;

import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.core.util.InnerSerializeUtils;
import cn.lg.soar.system.api.annotations.SysConfig;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.time.Duration;

/**
 * 系统配置接口
 * @author luguoxiang
 * @date 2021-08-11
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public interface ISysConfigApi {

    /**
     * 获取并缓存
     * @param code
     * @return
     */
    default String getByCache(String code) {
        return (String) CACHE.get(code, (k) -> get(k));
    }

    /**
     * 获取并缓存
     * @param code
     * @param defaultValue
     * @return
     */
    default String getByCache(String code, String defaultValue) {
        return (String) CACHE.get(code, (k) -> {
            String t = get(k);
            if (t == null) {
                return defaultValue;
            }
            return t;
        });
    }

    /**
     * 获取并缓存（缓存有效期120秒）
     * @param tClass
     * @return
     * @param <T>
     */
    default <T>T getByCache(Class<T> tClass) {
        SysConfig annotation = tClass.getAnnotation(SysConfig.class);
        AssertUtil.notNull(annotation, "请为配置类加上@SysConfig");
        Object o = CACHE.get(annotation.value(), (k) -> get(k, tClass));
        if (o == null) {
            return null;
        }
        return (T) o;
    }

    /**
     * 获取并缓存（缓存有效期120秒）
     * @param tClass
     * @param defaultValue 不存在时的默认值
     * @return
     * @param <T>
     */
    default <T>T getByCache(Class<T> tClass, T defaultValue) {
        SysConfig annotation = tClass.getAnnotation(SysConfig.class);
        AssertUtil.notNull(annotation, "请为配置类加上@SysConfig");
        return (T) CACHE.get(annotation.value(), (k) -> {
            T t = get(k, tClass);
            if (t == null) {
                return defaultValue;
            }
            return t;
        });
    }

    /**
     * 获取并缓存（缓存有效期120秒）
     * @param code
     * @param tClass
     * @return
     * @param <T>
     */
    default <T>T getByCache(String code, Class<T> tClass) {
        Object o = CACHE.get(code, (k) -> get(k, tClass));
        if (o == null) {
            return null;
        }
        return (T) o;
    }

    /**
     * 获取并缓存（缓存有效期120秒）
     * @param code
     * @param tClass
     * @param defaultValue 不存在时的默认值
     * @return
     * @param <T>
     */
    default <T>T getByCache(String code, Class<T> tClass, T defaultValue) {
        return (T) CACHE.get(code, (k) -> {
            T t = get(k, tClass);
            if (t == null) {
                return defaultValue;
            }
            return t;
        });
    }

    /**
     * 获取系统配置
     * @param code
     * @param tClass
     * @return
     * @param <T>
     */
    default <T>T get(String code, Class<T> tClass) {
        return InnerSerializeUtils.parseObject(get(code), tClass);
    }

    /**
     * 获取系统配置（默认读取注解 @SysConfig 获取code）
     * @param tClass
     * @return
     * @param <T>
     */
    default <T>T get(Class<T> tClass) {
        SysConfig annotation = tClass.getAnnotation(SysConfig.class);
        AssertUtil.notNull(annotation, "请为配置类加上@SysConfig");
        return get(annotation.value(), tClass);
    }

    /**
     * 设置配置
     * @param code
     * @param value
     * @return
     */
    default boolean set(String code, Object value) {
        CACHE.invalidate(code);
        return set(code, InnerSerializeUtils.toJson(value));
    }

    /**
     * 设置配置（默认读取注解 @SysConfig 获取code）
     * @param value 值
     * @return
     */
    default boolean set(Object value) {
        if (value == null) {
            return false;
        }
        SysConfig annotation = value.getClass().getAnnotation(SysConfig.class);
        AssertUtil.notNull(annotation, "请为配置类加上@SysConfig");
        CACHE.invalidate(annotation.value());
        return set(annotation.value(), value);
    }

    Cache<String, Object> CACHE = Caffeine.newBuilder()
            .initialCapacity(32)
            .maximumSize(1024)
            .expireAfterWrite(Duration.ofSeconds(120))
            .build();

    /**
     * 获取系统配置
     * @param code
     * @return
     */
    String get(String code);

    /**
     * 设置配置
     * @param code
     * @param value
     * @return
     */
    boolean set(String code, String value);
}
